home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / fsutil / fsutilHandle.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  37.5 KB  |  1,327 lines

  1. /* 
  2.  * fsutilHandle.c --
  3.  *
  4.  *    Routines to manage file handles.  They are kept in a table hashed
  5.  *    by the Fs_FileID type.  They are referenced counted and eligible for
  6.  *    removal when their reference count goes to zero.  Fsutil_HandleInstall
  7.  *    adds handles to the table.  Fsutil_HandleFetch returns a locked handle.
  8.  *    Fsutil_HandleLock locks a handle that you already have.
  9.  *    Installing initializes the refCount to 1, and Fetching increments it.
  10.  *    Use Fsutil_HandleUnlock and Fsutil_HandleReleaseHdr to unlock and
  11.  *    decrement the reference count, respectively.  The macros
  12.  *    Fsutil_HandleFetchType and Fsutil_HandleRelease do type casting and
  13.  *    are defined in fsInt.h.  Fsutil_HandleRemove deletes a handle from
  14.  *    the table, and Fsutil_GetNextHandle is used to iterate through the
  15.  *    whole hash table.
  16.  *
  17.  * Copyright 1986 Regents of the University of California.
  18.  * All rights reserved.
  19.  */
  20.  
  21. #ifndef lint
  22. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/fsutil/fsutilHandle.c,v 9.9 92/06/01 15:34:02 kupfer Exp $ SPRITE (Berkeley)";
  23. #endif not lint
  24.  
  25. #include <sprite.h>
  26. #include <fs.h>
  27. #include <fsutil.h>
  28. #include <fsStat.h>
  29. #include <fslcl.h>
  30. #include <fsdm.h>
  31. #include <fsio.h>
  32. #include <fsNameOps.h>
  33. #include <hash.h>
  34.  
  35. #include <string.h>
  36. #include <stdio.h>
  37.  
  38. static Sync_Lock handleTableLock = Sync_LockInitStatic("Fs:handleTable");
  39. #define    LOCKPTR    &handleTableLock
  40.  
  41. /*
  42.  * Synchronization and termination variables for LRU replacement.
  43.  */
  44. Sync_Condition lruDone;
  45. static Boolean lruInProgress;
  46. static int lruHandlesChecked;
  47. /*
  48.  * NOTE: The current implementation of handle scavenging leads to serious
  49.  * performance problems.  On systems with large file caches almost all the
  50.  * handles on the LRU will have files in the cache and wont be scavenged.
  51.  * Everytime a new handle needs to be created the entire LRU is scanned 
  52.  * before the code gives up and malloc's memory. This needs to be fixed. 
  53.  */
  54.  
  55. /*
  56.  * Hash tables for object handles.  These are kept in LRU order and
  57.  * a soft limit on their number is enforced.  If the number of handles
  58.  * gets beyond fs_Stats.handle.maxNumber then LRU replacement is done until
  59.  * handleScavengeThreashold are replaced.  If all handles are in
  60.  * use the max table size is allowed to grow by handleLimitInc.
  61.  * The table never shrinks on the premise that once it has grown the
  62.  * memory allocator establishes a high water mark and shrinking the table
  63.  * won't really help overall kernel memory usage.
  64.  */
  65. Hash_Table    fileHashTableStruct;
  66. Hash_Table    *fileHashTable = &fileHashTableStruct;
  67. static List_Links lruListHeader;
  68. static List_Links *lruList = &lruListHeader;
  69. /*
  70.  * FS_HANDLE_TABLE_SIZE is the initial size of the handle table.
  71.  *    Observation reveals that it takes about 120 handles to get
  72.  *    through multi-user bootstrap, and 135 to get through the first login.
  73.  *    Starting the window system jumps the number of handles to about 250.
  74.  *    Running a large compilation pushes the table up to about 450 handles.
  75.  *    The file servers ramp up to 2500 handles, but this is a
  76.  *    function of the activity of their clients and the number of
  77.  *    directories they have.
  78.  * LIMIT_INC defines the amount the table grows by
  79.  * THREASHOLD defines how many handles are reclaimed before stopping.  This
  80.  *    is set very low so in the steady state we don't waste much time
  81.  *    looking at un-reclaimable handles.
  82.  */
  83. #define        FS_HANDLE_TABLE_SIZE       400
  84.  
  85. #define        LIMIT_INC(max)           ( 100 )
  86. int        handleLimitInc =       LIMIT_INC(FS_HANDLE_TABLE_SIZE);
  87. #define        THREASHOLD(max)           ( 1 )
  88. int        handleScavengeThreashold = THREASHOLD(FS_HANDLE_TABLE_SIZE);
  89.  
  90. extern Fs_HandleHeader *GetNextLRUHandle _ARGS_((void));
  91. extern void DoneLRU _ARGS_((int numScavenged));
  92.  
  93. /*
  94.  * Flags for handles referenced from the hash table.
  95.  *    FS_HANDLE_INSTALLED - the structure has been put into the hash table.
  96.  *    FS_HANDLE_LOCKED    - the lock bit on the handle.  Handles are locked
  97.  *        when they are fetched from the hash table.
  98.  *    FS_HANDLE_REMOVED   - set instead of freeing the handle if the
  99.  *        remove procedure sees the 'wanted' or 'don't move' bit.
  100.  *    FS_HANDLE_INVALID   - set when a handle becomes invalid after
  101.  *        a recovery error.
  102.  *    FS_HANDLE_DONT_CACHE - set if the handle should be removed after
  103.  *        the last reference is released.
  104.  */
  105. #define FS_HANDLE_INSTALLED    0x1
  106. #define FS_HANDLE_LOCKED    0x2
  107. #define FS_HANDLE_REMOVED    0x8
  108. #define FS_HANDLE_FREED        0x10
  109. #define FS_HANDLE_INVALID    0x20
  110. #define FS_HANDLE_DONT_CACHE    0x40
  111.  
  112. /*
  113.  * LOCK_HANDLE --
  114.  * Macro to lock a file handle.   The handle lock is used during open/close
  115.  * and migration to serialize fetching, releasing, installing,
  116.  * and removing the handle.  Additionally, some object types use the
  117.  * handle lock for synchronization of I/O operations.
  118.  * If CLEAN is defined we don't remember the process ID of the locker,
  119.  * nor do we count events.
  120.  */
  121.  
  122. #ifdef CLEAN
  123.  
  124. #define    LOCK_HANDLE(hdrPtr) \
  125.     while (((hdrPtr)->flags & FS_HANDLE_LOCKED) && !sys_ShuttingDown) { \
  126.         (void) Sync_Wait(&((hdrPtr)->unlocked), FALSE); \
  127.     } \
  128.     (hdrPtr)->flags |= FS_HANDLE_LOCKED;
  129.  
  130. #else
  131.  
  132. #define LOCK_HANDLE(hdrPtr) \
  133.     while (((hdrPtr)->flags & FS_HANDLE_LOCKED) && !sys_ShuttingDown) { \
  134.         fs_Stats.handle.lockWaits++; \
  135.         (void) Sync_Wait(&((hdrPtr)->unlocked), FALSE); \
  136.     } \
  137.     fs_Stats.handle.locks++; \
  138.     (hdrPtr)->lockProcPtr = Proc_GetEffectiveProc(); \
  139.     (hdrPtr)->flags |= FS_HANDLE_LOCKED;
  140.  
  141. #endif
  142.  
  143. /*
  144.  * UNLOCK_HANDLE --
  145.  *    Unlock a handle so it can be fetched by another process.
  146.  *    This clears the lock bit and notifies the waiting condition.
  147.  */
  148.  
  149. #ifdef CLEAN
  150.  
  151. #define    UNLOCK_HANDLE(hdrPtr) \
  152.     (hdrPtr)->flags &= ~FS_HANDLE_LOCKED; \
  153.     Sync_Broadcast(&((hdrPtr)->unlocked));
  154.  
  155. #else
  156.  
  157. #define    UNLOCK_HANDLE(hdrPtr) \
  158.     (hdrPtr)->flags &= ~FS_HANDLE_LOCKED; \
  159.     (hdrPtr)->lockProcPtr = (Proc_ControlBlock *)NIL; \
  160.     fs_Stats.handle.unlocks++; \
  161.     Sync_Broadcast(&((hdrPtr)->unlocked));
  162.  
  163. #endif
  164. /*
  165.  * REMOVE_HANDLE --
  166.  * Macro to remove a handle, so no details get fogotten.  Note, removal
  167.  * from the hash table is separate, because we do that first, and then
  168.  * clean it up completely later with this macro.
  169.  */
  170.  
  171. #define REMOVE_HANDLE(hdrPtr) \
  172.     if ((hdrPtr)->lruLinks.nextPtr != (List_Links *)NIL) {    \
  173.         List_Remove(&(hdrPtr)->lruLinks);             \
  174.         fs_Stats.handle.lruEntries--;            \
  175.     }                            \
  176.     if ((hdrPtr)->name != (char *)NIL) {            \
  177.         free((hdrPtr)->name);                \
  178.     }                            \
  179.     free((char *)(hdrPtr));
  180.  
  181. /*
  182.  * MOVE_HANDLE --
  183.  * Macro to move a handle to the back (most recent) end of the LRU list.
  184.  * Not all handle types are in the LRU list, hence the check against NIL.
  185.  */
  186.  
  187. #define MOVE_HANDLE(hdrPtr) \
  188.         if ((hdrPtr)->lruLinks.nextPtr != (List_Links *)NIL) {    \
  189.         List_Move(&(hdrPtr)->lruLinks, LIST_ATREAR(lruList));    \
  190.         }
  191.  
  192. /*
  193.  * HDR_FILE_NAME --
  194.  * Macro to give name associated with a handle.
  195.  */
  196. #define HDR_FILE_NAME(hdrPtr) \
  197.     (((hdrPtr)->name == (char *)NIL) ? "(no name)" : hdrPtr->name)
  198.  
  199. extern Boolean HandleInstallInt _ARGS_((Fs_FileID *fileIDPtr, 
  200.         unsigned int handleLimit, Fs_HandleHeader **hdrPtrPtr, 
  201.         Boolean *foundPtr, Boolean returnLocked));
  202.  
  203.  
  204. /*
  205.  *----------------------------------------------------------------------------
  206.  *
  207.  * Fsutil_HandleInit --
  208.  *
  209.  *     Initialize the hash table.
  210.  *
  211.  * Results:
  212.  *    None.
  213.  *
  214.  * Side effects:
  215.  *    Hash table is initialized.
  216.  *
  217.  *----------------------------------------------------------------------------
  218.  */
  219.  
  220. void
  221. Fsutil_HandleInit(fileHashSize)
  222.     int    fileHashSize;    /* The number of hash table entries to put in the
  223.              * file hash table for starters. */
  224. {
  225.     /*
  226.      * Set the initial number of handle to be the maximum of 
  227.      * FS_HANDLE_TABLE_SIZE and 1/4 of the maximum number of blocks in the
  228.      * file cache.  This hack prevents the large overheads from
  229.      * the initial growing of the handle table. 
  230.      */
  231.     fs_Stats.handle.maxNumber = FS_HANDLE_TABLE_SIZE;
  232.     if (fs_Stats.handle.maxNumber < fs_Stats.blockCache.maxNumBlocks/4) {
  233.     fs_Stats.handle.maxNumber = fs_Stats.blockCache.maxNumBlocks/4;
  234.     }
  235.     List_Init(lruList);
  236.     Hash_Init(fileHashTable, fileHashSize, Hash_Size(sizeof(Fs_FileID)));
  237. }
  238.  
  239.  
  240. /*
  241.  *----------------------------------------------------------------------------
  242.  *
  243.  * Fsutil_HandleInstall --
  244.  *
  245.  *      Install a file handle given its fileID.  The caller is responsible
  246.  *    for initializing type-specific fields if this procedure returns
  247.  *    FALSE to indicate the handle was newly created.  The handle is
  248.  *    returned locked and with a single reference that has to be
  249.  *    released with Fsutil_HandleRelease.
  250.  *
  251.  * Results:
  252.  *    TRUE is returned if the file handle was already in the 
  253.  *    hash table.  Upon return, *hdrPtrPtr references the installed handle.
  254.  *
  255.  * Side effects:
  256.  *    New handle may be allocated and installed into the hash table.
  257.  *
  258.  *----------------------------------------------------------------------------
  259.  *
  260.  */
  261. ENTRY Boolean
  262. Fsutil_HandleInstall(fileIDPtr, size, name, cantBlock, hdrPtrPtr)
  263.     register Fs_FileID    *fileIDPtr;    /* Identfies handle to install. */
  264.     int             size;        /* True size of the handle.  This
  265.                      * routine only looks at the header,
  266.                      * but more data follows that. */
  267.     char        *name;        /* File name for error messages */
  268.     Boolean        cantBlock;    /* TRUE if this call shouldn't block
  269.                      * because the handle already is locked.
  270.                      */
  271.     Fs_HandleHeader    **hdrPtrPtr;    /* Return pointer to handle that
  272.                      * is found in the hash table. */
  273. {
  274.     Boolean found;
  275.     Boolean tableFull;
  276.     int numScavenged;
  277.     Fs_HandleHeader *hdrPtr;
  278.     Fs_HandleHeader *newHdrPtr = (Fs_HandleHeader *)NIL;
  279.     Boolean returnLocked = TRUE;    /* For now, always return locked */
  280.  
  281.     fs_Stats.handle.installCalls++;
  282.     do {
  283.     Boolean wouldWait;
  284.     /*
  285.      * Due to memory limitations we structure this so we malloc()
  286.      * outside the handle monitor lock.  That way we can still
  287.      * sync the disks if malloc fails.
  288.      * 1. Try a fetch.  This returns a locked handle, or NIL.
  289.      * 2. Allocate memory for the new handle.
  290.      * 3. Install the handle in the table.
  291.      * 4. If the install fails we do LRU replacment and loop to step 1.
  292.      */
  293.     if (cantBlock) { 
  294.         hdrPtr = Fsutil_HandleFetchNoWait(fileIDPtr, &wouldWait);
  295.         if ((hdrPtr == (Fs_HandleHeader *)NIL) && wouldWait) {
  296.         *hdrPtrPtr = hdrPtr;
  297.         return TRUE;
  298.         }
  299.     } else {
  300.         hdrPtr = Fsutil_HandleFetch(fileIDPtr);
  301.     }
  302.     if (hdrPtr != (Fs_HandleHeader *)NIL) {
  303.         found = TRUE;
  304.         break;
  305.     }
  306.     found = FALSE;
  307.     if (newHdrPtr == (Fs_HandleHeader *)NIL) {
  308.         newHdrPtr = (Fs_HandleHeader *)malloc(size);
  309.         if (name != (char *)NIL) {
  310.         newHdrPtr->name = (char *)malloc(strlen(name) + 1);
  311.         (void)strcpy(newHdrPtr->name, name);
  312.         } else {
  313.         newHdrPtr->name = (char *)NIL;
  314.         }
  315.     }
  316.     hdrPtr = newHdrPtr;
  317.     tableFull = HandleInstallInt(fileIDPtr, fs_Stats.handle.maxNumber,
  318.                      &hdrPtr, &found, returnLocked);
  319.     if (tableFull) {
  320.         /*
  321.          * Size limit would be exceeded.  Recycle some handles.  The
  322.          * new handle has not been installed into the hash table yet.
  323.          */
  324.         numScavenged = 0;
  325.         fs_Stats.handle.lruScans++;
  326.         for (hdrPtr = GetNextLRUHandle();
  327.          hdrPtr != (Fs_HandleHeader *)NIL;
  328.          hdrPtr = GetNextLRUHandle()) {
  329.         if ((*fsio_StreamOpTable[hdrPtr->fileID.type].scavenge)(hdrPtr)) {
  330.             numScavenged++;
  331.             fs_Stats.handle.lruHits++;
  332.             if (numScavenged >= handleScavengeThreashold) {
  333.             break;
  334.             }
  335.         } else {
  336.             fs_Stats.handle.lruChecks++;
  337.         }
  338.         }
  339.         /*
  340.          * Finish LRU, grow the table if needed, and then
  341.          * loop back and try to fetch or install the handle again.
  342.          */
  343.         DoneLRU(numScavenged);
  344.         hdrPtr = (Fs_HandleHeader *)NIL;
  345.     }
  346.     } while (hdrPtr == (Fs_HandleHeader *)NIL);
  347.  
  348.     if (found) {
  349.     /*
  350.      * Handle exists. Free up the handle we may have allocated.
  351.      * Adjust the name on the handle we found if we have a better one.
  352.      */
  353.     fs_Stats.handle.installHits++;
  354.     if (newHdrPtr != (Fs_HandleHeader *)NIL) {
  355.         if (newHdrPtr->name != (char *)NIL) {
  356.         free(newHdrPtr->name);
  357.         }
  358.         free((Address)newHdrPtr);
  359.     }
  360. #ifdef sun4c
  361.     if (name != (char *)NIL) {
  362.         if (hdrPtr->name != (char *) NIL) {
  363.         free(hdrPtr->name);
  364.         }
  365.         hdrPtr->name = (char *)malloc(strlen(name) + 1);
  366.         (void)strcpy(hdrPtr->name, name);
  367.     }
  368. #else
  369.     if ((hdrPtr->name == (char *)NIL) && (name != (char *)NIL)) {
  370.         hdrPtr->name = (char *)malloc(strlen(name) + 1);
  371.         (void)strcpy(hdrPtr->name, name);
  372.     }
  373. #endif /* sun4c */
  374.     }
  375.     *hdrPtrPtr = hdrPtr;
  376.     return(found);
  377. }
  378.  
  379. /*
  380.  *----------------------------------------------------------------------------
  381.  *
  382.  * HandleInstallInt --
  383.  *
  384.  *      Install a file handle.  This enforces a soft limit on the number
  385.  *    of handles that can exist.  Our caller has to allocate space for
  386.  *    the handle.
  387.  *
  388.  * Results:
  389.  *    TRUE is returned if the file handle table was full and our
  390.  *    caller should do LRU replacement on the table.
  391.  *    *foundPtr is set to TRUE if the handle was found.  This is possible
  392.  *    on a multiprossor even if our caller has first tried a fetch.
  393.  *
  394.  * Side effects:
  395.  *    The new handle is installed into the hash table.
  396.  *
  397.  *----------------------------------------------------------------------------
  398.  *
  399.  */
  400. ENTRY Boolean
  401. HandleInstallInt(fileIDPtr, handleLimit, hdrPtrPtr, foundPtr, returnLocked)
  402.     register Fs_FileID    *fileIDPtr;    /* Identfies handle to install. */
  403.     unsigned int    handleLimit;    /* Determines how many handles can
  404.                      * exist before we return NULL */
  405.     Fs_HandleHeader    **hdrPtrPtr;    /* In - handle to install into table
  406.                      * Out - handle found in table. */    
  407.     Boolean        *foundPtr;    /* TRUE upon return if handle found */
  408.     Boolean        returnLocked;    /* TRUE the handle is locked upon
  409.                      * return.  Otherwise it is not
  410.                      * locked, but its reference count
  411.                      * is up so it won't go away. */
  412. {
  413.     register    Hash_Entry    *hashEntryPtr;
  414.     register    Fs_HandleHeader    *hdrPtr;
  415.     Boolean            tableFull = FALSE;
  416.     Boolean            found;
  417.  
  418.     LOCK_MONITOR;
  419. again:
  420.     if (fs_Stats.handle.exists >= handleLimit) {
  421.     /*
  422.      * Creating a handle will push us past the soft limit on handles.
  423.      * We just look into the hash table, but do not create a new
  424.      * entry if the handle isn't found.
  425.      */
  426.     hashEntryPtr = Hash_LookOnly(fileHashTable, (Address) fileIDPtr);
  427.     if (hashEntryPtr == (Hash_Entry *)NIL) {
  428.         /*
  429.          * Table is full so our caller has to do LRU replacement.
  430.          * If LRU is already in progress we wait so there is only
  431.          * one process scanning the table at a time.
  432.          */
  433.         if (lruInProgress) {
  434.         do {
  435.             (void)Sync_Wait(&lruDone, FALSE);
  436.         } while (lruInProgress);
  437.         goto again;
  438.         } else {
  439.         lruInProgress = TRUE;
  440.         lruHandlesChecked = 0;
  441.         found = FALSE;
  442.         tableFull = TRUE;
  443.         goto exit;
  444.         }
  445.     }
  446.     } else {
  447.     /*
  448.      * Lookup the handle.  If a hash table entry doesn't exist
  449.      * it will be created by Hash_Find.
  450.      */
  451.     hashEntryPtr = Hash_Find(fileHashTable, (Address) fileIDPtr);
  452.     }
  453.     if (hashEntryPtr->value == (Address) NIL) {
  454.     /*
  455.      * Initialize the newly created file handle.  Our caller has
  456.      * allocated the space for the new handle.
  457.      */
  458.     hdrPtr = *hdrPtrPtr;
  459.     Hash_SetValue(hashEntryPtr, hdrPtr);
  460.     found = FALSE;
  461.     fs_Stats.handle.created++;
  462.     fs_Stats.handle.exists++;
  463.  
  464.     hdrPtr->fileID = *fileIDPtr;
  465.     hdrPtr->flags = FS_HANDLE_INSTALLED;
  466.     hdrPtr->unlocked.waiting = FALSE;
  467.     hdrPtr->refCount = 1;
  468.     /*
  469.      * Put the handle in the LRU list only if it has a scavenging
  470.      * routine defined for it.  This allows us to avoid checking
  471.      * un-reclaimable things.
  472.      */
  473.     if (fsio_StreamOpTable[fileIDPtr->type].scavenge != (Boolean (*)())NIL) {
  474.         List_InitElement(&hdrPtr->lruLinks);
  475.         List_Insert(&hdrPtr->lruLinks, LIST_ATREAR(lruList));
  476.         fs_Stats.handle.lruEntries++;
  477.     } else {
  478.         hdrPtr->lruLinks.nextPtr = (List_Links *)NIL;
  479.         hdrPtr->lruLinks.prevPtr = (List_Links *)NIL;
  480.     }
  481.     } else {
  482.     hdrPtr = (Fs_HandleHeader *) Hash_GetValue(hashEntryPtr);
  483.     if (hdrPtr->flags & FS_HANDLE_LOCKED) {
  484.         /*
  485.          * Wait for it to become unlocked.  We can't increment the
  486.          * the reference count until it is unlocked because it
  487.          * may be getting deleted.  If its locked we wait and retry.
  488.          */
  489.         (void) Sync_Wait(&hdrPtr->unlocked, FALSE);
  490.         fs_Stats.handle.lockWaits++;
  491.         goto again;
  492.     }
  493.     found = TRUE;
  494.     hdrPtr->refCount++;
  495.     MOVE_HANDLE(hdrPtr);
  496.     *hdrPtrPtr = hdrPtr;
  497.     }
  498.     if (returnLocked) {
  499.     LOCK_HANDLE(hdrPtr);
  500.     }
  501. exit:
  502.     *foundPtr = found;
  503.     UNLOCK_MONITOR;
  504.     return(tableFull);
  505. }
  506.  
  507. /*
  508.  *----------------------------------------------------------------------------
  509.  *
  510.  * Fsutil_HandleFetch --
  511.  * Fsutil_HandleFetchType --
  512.  *
  513.  *    Return a pointer to a file handle out of the file handle hash table.  
  514.  *    If no file handle is found then NIL is returned.  If one is found
  515.  *    then it is returned locked.  The reference count is increased
  516.  *    on the handle so it needs to be released with Fsutil_HandleRelease.
  517.  *    Fsutil_HandleFetchType is a macro that does type casting, see fsInt.h 
  518.  *
  519.  * Results:
  520.  *    A pointer to a file handle, NIL if none found.
  521.  *
  522.  * Side effects:
  523.  *    Locks the handle and increments its reference count.  The handle
  524.  *    is also moved to the end of the LRU list.
  525.  *
  526.  *----------------------------------------------------------------------------
  527.  *
  528.  */
  529. ENTRY Fs_HandleHeader *
  530. Fsutil_HandleFetch(fileIDPtr)
  531.     Fs_FileID     *fileIDPtr;    /* Identfies handle to fetch. */
  532. {
  533.     Hash_Entry    *hashEntryPtr;
  534.     Fs_HandleHeader    *hdrPtr;
  535.  
  536.     LOCK_MONITOR;
  537.  
  538.     fs_Stats.handle.fetchCalls++;
  539.  
  540. again:
  541.     /*
  542.      * Look in the hash table.  A bucket might have been installed by
  543.      * Fsutil_HandleInstall, but the value might be NIL because the
  544.      * handle table's size would have been exceeded by creating the handle.
  545.      */
  546.     hdrPtr = (Fs_HandleHeader *)NIL;
  547.     hashEntryPtr = Hash_LookOnly(fileHashTable, (Address) fileIDPtr);
  548.     if (hashEntryPtr != (Hash_Entry *) NIL) {
  549.     hdrPtr = (Fs_HandleHeader *) Hash_GetValue(hashEntryPtr);
  550.     if (hdrPtr != (Fs_HandleHeader *)NIL) {
  551.         fs_Stats.handle.fetchHits++;
  552.         if (hdrPtr->flags & FS_HANDLE_LOCKED) {
  553.         /*
  554.          * Wait for it to become unlocked and then rehash.
  555.          * The handle could get removed before we get a chance
  556.          * to increment the reference count on it.
  557.          */
  558.         fs_Stats.handle.lockWaits++;
  559.         (void) Sync_Wait(&hdrPtr->unlocked, FALSE);
  560.         goto again;
  561.         }
  562.         MOVE_HANDLE(hdrPtr);
  563.         LOCK_HANDLE(hdrPtr);
  564.         hdrPtr->refCount++;
  565.     }
  566.     }
  567.     UNLOCK_MONITOR;
  568.     return(hdrPtr);
  569. }
  570.  
  571. /*
  572.  *----------------------------------------------------------------------------
  573.  *
  574.  * Fsutil_HandleFetchNoWait --
  575.  *
  576.  *    This routine does the same thing as Fsutil_HandleFetch except that
  577.  *    it wouldn't wait around for a handle to because unlocked.
  578.  *
  579.  * Results:
  580.  *    A pointer to a file handle, NIL if none found or handle locked.
  581.  *
  582.  * Side effects:
  583.  *    Locks the handle and increments its reference count.  The handle
  584.  *    is also moved to the end of the LRU list.
  585.  *
  586.  *----------------------------------------------------------------------------
  587.  *
  588.  */
  589. ENTRY Fs_HandleHeader *
  590. Fsutil_HandleFetchNoWait(fileIDPtr, wouldWaitPtr)
  591.     Fs_FileID     *fileIDPtr;    /* Identfies handle to fetch. */
  592.     Boolean    *wouldWaitPtr;  /* OUT: Set to TRUE if call would of waited. */
  593. {
  594.     Hash_Entry    *hashEntryPtr;
  595.     Fs_HandleHeader    *hdrPtr;
  596.  
  597.     LOCK_MONITOR;
  598.  
  599.     fs_Stats.handle.fetchCalls++;
  600.  
  601.     /*
  602.      * Look in the hash table.  A bucket might have been installed by
  603.      * Fsutil_HandleInstall, but the value might be NIL because the
  604.      * handle table's size would have been exceeded by creating the handle.
  605.      */
  606.     *wouldWaitPtr = FALSE;
  607.     hdrPtr = (Fs_HandleHeader *)NIL;
  608.     hashEntryPtr = Hash_LookOnly(fileHashTable, (Address) fileIDPtr);
  609.     if (hashEntryPtr != (Hash_Entry *) NIL) {
  610.     hdrPtr = (Fs_HandleHeader *) Hash_GetValue(hashEntryPtr);
  611.     if (hdrPtr != (Fs_HandleHeader *)NIL) {
  612.         fs_Stats.handle.fetchHits++;
  613.         if (hdrPtr->flags & FS_HANDLE_LOCKED) {
  614.         *wouldWaitPtr = TRUE;
  615.         UNLOCK_MONITOR;
  616.         return (Fs_HandleHeader *) NIL;
  617.         }
  618.         MOVE_HANDLE(hdrPtr);
  619.         LOCK_HANDLE(hdrPtr);
  620.         hdrPtr->refCount++;
  621.     }
  622.     }
  623.     UNLOCK_MONITOR;
  624.     return(hdrPtr);
  625. }
  626.  
  627. /*
  628.  *----------------------------------------------------------------------------
  629.  *
  630.  * Fsutil_HandleLockHdr --
  631.  * Fsutil_HandleLock --
  632.  *
  633.  *    Get a lock on the handle.  Fsutil_HandleLock is a macro defined in fsInt.h
  634.  *
  635.  * Results:
  636.  *    None.
  637.  *
  638.  * Side effects:
  639.  *    The lock bit is added to the flags field for the handle.
  640.  *
  641.  *----------------------------------------------------------------------------
  642.  *
  643.  */
  644. ENTRY void
  645. Fsutil_HandleLockHdr(hdrPtr)
  646.     register    Fs_HandleHeader    *hdrPtr;
  647. {
  648.     LOCK_MONITOR;
  649.  
  650.     LOCK_HANDLE(hdrPtr);
  651.  
  652.     UNLOCK_MONITOR;
  653. }
  654.  
  655. /*
  656.  *----------------------------------------------------------------------------
  657.  *
  658.  * Fsutil_HandleIncRefCount --
  659.  *
  660.  *    Increment the reference count on the handle.  This is used by
  661.  *    the name hash table when a handle is put there.
  662.  *
  663.  * Results:
  664.  *    None.
  665.  *
  666.  * Side effects:
  667.  *    The reference count on the handle is incremented.
  668.  *
  669.  *----------------------------------------------------------------------------
  670.  *
  671.  */
  672. ENTRY void
  673. Fsutil_HandleIncRefCount(hdrPtr, amount)
  674.     register    Fs_HandleHeader    *hdrPtr;
  675.     int             amount;
  676. {
  677.     LOCK_MONITOR;
  678.  
  679.     hdrPtr->refCount += amount;
  680.  
  681.     UNLOCK_MONITOR;
  682. }
  683.  
  684. /*
  685.  *----------------------------------------------------------------------------
  686.  *
  687.  * Fsutil_HandleDecRefCount --
  688.  *
  689.  *    Decrement the reference count on the handle.
  690.  *    This is like releasing a handle but the locks on the handle
  691.  *    are not disturbed.  This is used when removing entries from
  692.  *    the name component hash table and during migration.
  693.  *
  694.  * Results:
  695.  *    None.
  696.  *
  697.  * Side effects:
  698.  *    The reference count on the handle is decremented.
  699.  *
  700.  *----------------------------------------------------------------------------
  701.  *
  702.  */
  703. ENTRY void
  704. Fsutil_HandleDecRefCount(hdrPtr)
  705.     register    Fs_HandleHeader    *hdrPtr;
  706. {
  707.     LOCK_MONITOR;
  708.  
  709.     hdrPtr->refCount--;
  710.  
  711.     UNLOCK_MONITOR;
  712. }
  713.  
  714. /*
  715.  *----------------------------------------------------------------------------
  716.  *
  717.  * Fsutil_HandleDup --
  718.  *
  719.  *    Duplicate a reference to a handle.  This locks the handle and
  720.  *    increments the refCount.  This is used by the local lookup routine
  721.  *    as it initiates its path search.
  722.  *
  723.  * Results:
  724.  *    None.
  725.  *
  726.  * Side effects:
  727.  *    The reference count on the handle is incremented and the handle is
  728.  *    locked.
  729.  *
  730.  *----------------------------------------------------------------------------
  731.  *
  732.  */
  733. ENTRY Fs_HandleHeader *
  734. Fsutil_HandleDup(hdrPtr)
  735.     register    Fs_HandleHeader    *hdrPtr;
  736. {
  737.     LOCK_MONITOR;
  738.  
  739.     LOCK_HANDLE(hdrPtr);
  740.     MOVE_HANDLE(hdrPtr);
  741.     hdrPtr->refCount++;
  742.  
  743.     UNLOCK_MONITOR;
  744.     return(hdrPtr);
  745. }
  746.  
  747. /*
  748.  *----------------------------------------------------------------------------
  749.  *
  750.  * Fsutil_HandleValid --
  751.  *
  752.  *    See if a handle have been marked invalid because of recovery.
  753.  *
  754.  * Results:
  755.  *    TRUE if the handle is still good.  FALSE if it's been marked invalid.
  756.  *
  757.  * Side effects:
  758.  *    None.
  759.  *
  760.  *----------------------------------------------------------------------------
  761.  *
  762.  */
  763.  
  764. ENTRY Boolean
  765. Fsutil_HandleValid(hdrPtr)
  766.     register Fs_HandleHeader *hdrPtr;    /* Handle to check. */
  767. {
  768.     register Boolean valid;
  769.     LOCK_MONITOR;
  770.     valid = ( (hdrPtr->flags & FS_HANDLE_INVALID) == 0 );
  771.     UNLOCK_MONITOR;
  772.     return(valid);
  773. }
  774.  
  775. /*
  776.  *----------------------------------------------------------------------------
  777.  *
  778.  * Fsutil_HandleUnlockHdr --
  779.  * Fsutil_HandleUnlock --
  780.  *
  781.  *    Release the lock on the handle. Fsutil_HandleUnlock is a macro defined
  782.  *    in fsInt.h that does type casting.
  783.  *
  784.  * Results:
  785.  *    FALSE because this is used as a scavenging no-op.
  786.  *
  787.  * Side effects:
  788.  *    The lock bit is removed from the flags filed for the handle.
  789.  *
  790.  *----------------------------------------------------------------------------
  791.  *
  792.  */
  793. ENTRY Boolean
  794. Fsutil_HandleUnlockHdr(hdrPtr)
  795.     register    Fs_HandleHeader    *hdrPtr;
  796. {
  797.     LOCK_MONITOR;
  798.  
  799.     if ((hdrPtr->flags & FS_HANDLE_LOCKED) == 0) {
  800.     UNLOCK_MONITOR;
  801.     panic( "HandleUnlock, un-locked handle\n");
  802.     return(FALSE);
  803.     }
  804.     UNLOCK_HANDLE(hdrPtr);
  805.  
  806.     UNLOCK_MONITOR;
  807.     return(FALSE);
  808. }
  809.  
  810. /*
  811.  *----------------------------------------------------------------------------
  812.  *
  813.  * Fsutil_HandleReleaseHdr --
  814.  * Fsutil_HandleRelease --
  815.  *
  816.  *    Fsutil_HandleRelease is a macro that does type casting, see fsInt.h
  817.  *    Decrement the reference count on the file handle.  The caller specifies
  818.  *    if the handle is already locked, in which case it is unlocked.
  819.  *
  820.  * Results:
  821.  *    None.
  822.  *
  823.  * Side effects:
  824.  *    The reference count is decremented.  If the reference count goes
  825.  *    to zero    and the handle has been removed then it gets nuked here.
  826.  *
  827.  *----------------------------------------------------------------------------
  828.  *
  829.  */
  830. ENTRY void
  831. Fsutil_HandleReleaseHdr(hdrPtr, locked)
  832.     register Fs_HandleHeader *hdrPtr;  /* Header of handle to release. */
  833.     Boolean          locked;       /* TRUE if the handle is already locked. */
  834. {
  835.     LOCK_MONITOR;
  836.     fs_Stats.handle.release++;
  837.  
  838.     if (locked && ((hdrPtr->flags & FS_HANDLE_LOCKED) == 0)) {
  839.     UNLOCK_MONITOR;
  840.     panic("HandleRelease, handle <%d,%d,%d,%d> \"%s\" not locked\n",
  841.         hdrPtr->fileID.type, hdrPtr->fileID.serverID,
  842.         hdrPtr->fileID.major, hdrPtr->fileID.minor, HDR_FILE_NAME(hdrPtr));
  843.     return;
  844.     }
  845.     hdrPtr->refCount--;
  846.  
  847.     if (hdrPtr->refCount < 0) {
  848.     UNLOCK_MONITOR;
  849.     panic("refCount %d on %s handle <%d,%d,%d> \"%s\"\n",
  850.         hdrPtr->refCount, Fsutil_FileTypeToString(hdrPtr->fileID.type),
  851.         hdrPtr->fileID.serverID, hdrPtr->fileID.major,
  852.         hdrPtr->fileID.minor, HDR_FILE_NAME(hdrPtr));
  853.     return;
  854.     } else if ((hdrPtr->refCount == 0) &&
  855.            (hdrPtr->flags & FS_HANDLE_REMOVED)) {
  856.     /*
  857.      * The handle has been removed, and we are the last reference.
  858.      */
  859.     fs_Stats.handle.limbo--;
  860.         REMOVE_HANDLE(hdrPtr);
  861.      } else {
  862.     if (locked) {
  863.         UNLOCK_HANDLE(hdrPtr);
  864.     }
  865.     }
  866.     UNLOCK_MONITOR;
  867. }
  868.  
  869. /*
  870.  *----------------------------------------------------------------------------
  871.  *
  872.  * Fsutil_HandleRemoveInt --
  873.  *
  874.  *    Delete the handle from hash table.  The internal version that
  875.  *    knows it's under the monitor lock.  This can be called while
  876.  *    the handle still has references.  It unlocks the handle
  877.  *    and frees it if there are not references
  878.  *
  879.  * Results:
  880.  *    None.
  881.  *
  882.  * Side effects:
  883.  *    The file handle is deleted out of the hash table, and memory is freed
  884.  *    if there are no references to the handle.
  885.  *
  886.  *----------------------------------------------------------------------------
  887.  *
  888.  */
  889. INTERNAL void
  890. Fsutil_HandleRemoveInt(hdrPtr)
  891.     register Fs_HandleHeader *hdrPtr;  /* Header of handle to remove. */
  892. {
  893.     register    Hash_Entry    *hashEntryPtr;
  894.  
  895.     if (!(hdrPtr->flags & FS_HANDLE_INVALID)) {
  896.     hashEntryPtr = Hash_LookOnly(fileHashTable, (Address) &hdrPtr->fileID);
  897.     if (hashEntryPtr == (Hash_Entry *) NIL) {
  898.         UNLOCK_MONITOR;
  899.         panic("Fsutil_HandleRemoveInt: Couldn't find handle in hash table.\n");
  900.         LOCK_MONITOR;
  901.         return;
  902.     }
  903.     Hash_SetValue(hashEntryPtr, NIL);
  904.     Hash_Delete(fileHashTable, hashEntryPtr);
  905.     }
  906.     fs_Stats.handle.exists--;
  907.  
  908.     /*
  909.      * Wakeup anyone waiting for this handle to become unlocked.
  910.      */
  911.     UNLOCK_HANDLE(hdrPtr);
  912.  
  913.     if (hdrPtr->refCount > 0) {
  914.     /*
  915.      * We've removed the handle from the hash table so it won't
  916.      * be found, but someone has a reference to it.  HandleRelease
  917.      * will free the handle for us later.
  918.      */
  919.     fs_Stats.handle.limbo++;
  920.     hdrPtr->flags |= FS_HANDLE_REMOVED;
  921.     } else {
  922.     REMOVE_HANDLE(hdrPtr);
  923.     }
  924. }
  925.  
  926. /*
  927.  *----------------------------------------------------------------------------
  928.  *
  929.  * Fsutil_HandleRemove --
  930.  * Fsutil_HandleRemoveHdr --
  931.  *
  932.  *    Delete the handle from hash table by calling the internal routine.
  933.  *    Fsutil_HandleRemove is a macro defined in fsInt.h that does type casting.
  934.  *    Removing a handle deletes it from the hash table and unlocks it.
  935.  *    Then, if there are no references to the handle it is freed.  Otherwise
  936.  *    it is marked as deleted and Fsutil_HandleRelease cleans it up.
  937.  *
  938.  * Results:
  939.  *    None.
  940.  *
  941.  * Side effects:
  942.  *    None (see Fsutil_HandleRemoveInt).
  943.  *
  944.  *----------------------------------------------------------------------------
  945.  *
  946.  */
  947.  
  948. ENTRY void
  949. Fsutil_HandleRemoveHdr(hdrPtr)
  950.     register Fs_HandleHeader *hdrPtr;    /* Handle to remove. */
  951. {
  952.     LOCK_MONITOR;
  953.     Fsutil_HandleRemoveInt(hdrPtr);
  954.     UNLOCK_MONITOR;
  955. }
  956.  
  957. /*
  958.  *----------------------------------------------------------------------------
  959.  *
  960.  * Fsutil_HandleAttemptRemove --
  961.  *
  962.  *    Like Fsutil_HandleRemove, but specific to local file handles because
  963.  *    they might have extra references from the name component cache.
  964.  *    This will not remove the handle if it is still referenced from
  965.  *    that cache.  The reference count has to be checked inside the
  966.  *    monitor to avoid multi-processor races.    This routine is called by the
  967.  *    scavenging routines if they think it's probably ok to remove the handle.
  968.  *
  969.  * Results:
  970.  *    TRUE if it actually removed the handle.
  971.  *
  972.  * Side effects:
  973.  *    Frees the memory for the handles file descriptor.
  974.  *
  975.  *----------------------------------------------------------------------------
  976.  *
  977.  */
  978.  
  979. ENTRY Boolean
  980. Fsutil_HandleAttemptRemove(hdrPtr)
  981.     Fs_HandleHeader *hdrPtr; /* Handle to try and remove. */
  982. {
  983.     register Fsio_FileIOHandle *handlePtr;    
  984.     register Boolean removed;
  985.  
  986.     handlePtr = (Fsio_FileIOHandle *) hdrPtr;
  987.     LOCK_MONITOR;
  988.     if (handlePtr->hdr.refCount == 0) {
  989.     free((Address)handlePtr->descPtr);
  990.     handlePtr->descPtr = (Fsdm_FileDescriptor *)NIL;
  991.     Fsio_FileSyncLockCleanup(handlePtr);
  992.     Fsutil_HandleRemoveInt((Fs_HandleHeader *)handlePtr);
  993.     removed = TRUE;
  994.     } else {
  995.     removed = FALSE;
  996.     UNLOCK_HANDLE((Fs_HandleHeader *)handlePtr);
  997.     }
  998.     UNLOCK_MONITOR;
  999.     return(removed);
  1000. }
  1001.  
  1002. /*
  1003.  *----------------------------------------------------------------------------
  1004.  *
  1005.  * Fsutil_GetNextHandle --
  1006.  *
  1007.  *    Get the next handle in the hash table.  Return the handle locked.
  1008.  *    The hashSearchPtr is initialized with Hash_StartSearch.  This
  1009.  *    always skips locked handles.  The users of this routine are:
  1010.  *    recovery stuff:  it is important not to block recovery as
  1011.  *        that ends up hanging the whole machine.
  1012.  *    unmounting a disk: this is a rare operation, but it should not
  1013.  *        be hung-up by a wedged handle.
  1014.  *    scavenging:  if a handle is locked, then it should not
  1015.  *        be scavenged anyway.
  1016.  *
  1017.  * Results:
  1018.  *    The next handle in the hash table.
  1019.  *
  1020.  * Side effects:
  1021.  *    Locks the handle (but does not increment its reference count).
  1022.  *    This prints a warning if a handle is skipped when locked.
  1023.  *
  1024.  *----------------------------------------------------------------------------
  1025.  *
  1026.  */
  1027.  
  1028. ENTRY Fs_HandleHeader *
  1029. Fsutil_GetNextHandle(hashSearchPtr)
  1030.     Hash_Search    *hashSearchPtr;    /* Iterator for going through the hash table. */
  1031. {
  1032.     register     Fs_HandleHeader    *hdrPtr;
  1033.     register    Hash_Entry    *hashEntryPtr;
  1034.  
  1035.     LOCK_MONITOR;
  1036.  
  1037.     for (hashEntryPtr = Hash_Next(fileHashTable, hashSearchPtr);
  1038.          hashEntryPtr != (Hash_Entry *) NIL;  
  1039.      hashEntryPtr = Hash_Next(fileHashTable, hashSearchPtr)) {
  1040.     hdrPtr = (Fs_HandleHeader *) Hash_GetValue(hashEntryPtr);
  1041.     if (hdrPtr == (Fs_HandleHeader *)NIL) {
  1042.         /*
  1043.          * Caught handle in the process of being installed.
  1044.          */
  1045.         continue;
  1046.     }
  1047.     /*
  1048.      * Skip locked handles to avoid hanging the system on locked handle. 
  1049.      */
  1050.     if (hdrPtr->flags & FS_HANDLE_LOCKED) {
  1051.         continue;
  1052.     }
  1053.     if (hdrPtr->flags & (FS_HANDLE_INVALID|FS_HANDLE_REMOVED)) {
  1054.         continue;
  1055.     }
  1056.     LOCK_HANDLE(hdrPtr);
  1057.     UNLOCK_MONITOR;
  1058.     return(hdrPtr);
  1059.     }
  1060.  
  1061.     UNLOCK_MONITOR;
  1062.     return((Fs_HandleHeader *) NIL);
  1063. }
  1064.  
  1065. /*
  1066.  *----------------------------------------------------------------------------
  1067.  *
  1068.  * GetNextLRUHandle --
  1069.  *
  1070.  *    Get the next handle in the LRU list.  Return the handle locked.
  1071.  *    This skips locked handles because they are obviously in use and not good
  1072.  *    candidates for removal.  This also prevents a single locked handle
  1073.  *    from clogging up the system.
  1074.  *
  1075.  * Results:
  1076.  *    The next handle in the LRU list.
  1077.  *
  1078.  * Side effects:
  1079.  *    Increments the number of handles checked in this LRU scan so
  1080.  *    we know when to terminate.
  1081.  *
  1082.  *----------------------------------------------------------------------------
  1083.  *
  1084.  */
  1085. ENTRY Fs_HandleHeader *
  1086. GetNextLRUHandle()
  1087. {
  1088.     register     Fs_HandleHeader    *hdrPtr;
  1089.     register    List_Links    *listPtr;
  1090.  
  1091.     LOCK_MONITOR;
  1092.     if (lruHandlesChecked >= fs_Stats.handle.maxNumber) {
  1093.     hdrPtr = (Fs_HandleHeader *)NIL;
  1094.     goto exit;
  1095.     }
  1096.     /*
  1097.      * Get the candidate handle and move it to the young end of
  1098.      * the list in case it is not replaced.
  1099.      */
  1100.     listPtr = List_First(lruList);
  1101.     hdrPtr = LRU_LINKS_TO_HANDLE(listPtr);
  1102.     MOVE_HANDLE(hdrPtr);
  1103.     lruHandlesChecked++;
  1104.     /*
  1105.      * Now skip over locked and removed handles, moving them to the "young" end.
  1106.      */
  1107.     while (hdrPtr->flags & (FS_HANDLE_REMOVED|FS_HANDLE_LOCKED)) {
  1108.     if (lruHandlesChecked >= fs_Stats.handle.maxNumber) {
  1109.         hdrPtr = (Fs_HandleHeader *)NIL;
  1110.         goto exit;
  1111.     } else {
  1112.         listPtr = List_First(lruList);
  1113.         hdrPtr = LRU_LINKS_TO_HANDLE(listPtr);
  1114.         MOVE_HANDLE(hdrPtr);
  1115.     }
  1116.     lruHandlesChecked++;
  1117.     }
  1118.     LOCK_HANDLE(hdrPtr);
  1119. exit:
  1120.     UNLOCK_MONITOR;
  1121.     return(hdrPtr);
  1122. }
  1123.  
  1124. /*
  1125.  *----------------------------------------------------------------------------
  1126.  *
  1127.  * DoneLRU --
  1128.  *
  1129.  *    Terminate LRU iteration.  This grows the table if needed and
  1130.  *    then notifies anyone waiting for LRU replacement to finish.
  1131.  *
  1132.  * Results:
  1133.  *    None.
  1134.  *
  1135.  * Side effects:
  1136.  *    Grows the table if it needs to be grown.
  1137.  *
  1138.  *----------------------------------------------------------------------------
  1139.  *
  1140.  */
  1141. ENTRY void
  1142. DoneLRU(numScavenged)
  1143.     int numScavenged;        /* Number of handles replaced */
  1144. {
  1145.     LOCK_MONITOR;
  1146.     if (numScavenged == 0) {
  1147.     /*
  1148.      * Grow the table a bit because no handles could be reclaimed.
  1149.      */
  1150.     fs_Stats.handle.maxNumber += handleLimitInc;
  1151.     handleLimitInc = LIMIT_INC(fs_Stats.handle.maxNumber);
  1152.     handleScavengeThreashold = THREASHOLD(fs_Stats.handle.maxNumber);
  1153.     }
  1154.     lruInProgress = FALSE;
  1155.     Sync_Broadcast(&lruDone);
  1156.     UNLOCK_MONITOR;
  1157. }
  1158.  
  1159. /*
  1160.  *----------------------------------------------------------------------------
  1161.  *
  1162.  * Fsutil_HandleInvalidate --
  1163.  *
  1164.  *    Mark a handle as bogus because of a failed recovery attempt.
  1165.  *
  1166.  * Results:
  1167.  *    None.
  1168.  *
  1169.  * Side effects:
  1170.  *    Sets the INVALID flag in the handle, negates the minor
  1171.  *    field of the fileID so that the handle won't get found,
  1172.  *    removes the handle from the hash table.
  1173.  *
  1174.  *----------------------------------------------------------------------------
  1175.  *
  1176.  */
  1177. ENTRY void
  1178. Fsutil_HandleInvalidate(hdrPtr)
  1179.     Fs_HandleHeader *hdrPtr;
  1180. {
  1181.     Hash_Entry    *hashEntryPtr;
  1182.  
  1183.     LOCK_MONITOR;
  1184.  
  1185.     if ((hdrPtr->flags & FS_HANDLE_INVALID) == 0) {
  1186.     hdrPtr->flags |= FS_HANDLE_INVALID;
  1187.     /*
  1188.      * Invalid handles are deleted from the hash table and the fileID is
  1189.      * smashed so that all subsequent operations using this handle that
  1190.      * go to the server will fail with a stale handle return code.
  1191.      */
  1192.     hashEntryPtr = Hash_LookOnly(fileHashTable, (Address) &hdrPtr->fileID);
  1193.     if (hashEntryPtr == (Hash_Entry *) NIL) {
  1194.         UNLOCK_MONITOR;
  1195.         panic("Fsutil_HandleInvalidate: Can't find %s handle <%d,%d,%d>\n",
  1196.             Fsutil_FileTypeToString(hdrPtr->fileID.type),
  1197.             hdrPtr->fileID.serverID,
  1198.             hdrPtr->fileID.major, hdrPtr->fileID.minor);
  1199.         return;
  1200.     }
  1201.     Hash_SetValue(hashEntryPtr, NIL);
  1202.     Hash_Delete(fileHashTable, hashEntryPtr);
  1203.     hdrPtr->fileID.minor = -hdrPtr->fileID.minor;
  1204.     if (hdrPtr->name != (char *) NIL) {
  1205.         free(hdrPtr->name);
  1206.         hdrPtr->name = (char *) NIL;
  1207.     }   
  1208.     }
  1209.  
  1210.     UNLOCK_MONITOR;
  1211. }
  1212.  
  1213.  
  1214. /*
  1215.  *----------------------------------------------------------------------------
  1216.  *
  1217.  * Fsutil_HandleDescWriteBack --
  1218.  *
  1219.  *    Go through all of the handles and write back all descriptors that
  1220.  *    are dirty and have a modify date before the given time.
  1221.  *
  1222.  * Results:
  1223.  *    The number of locked file handles.
  1224.  *
  1225.  * Side effects:
  1226.  *    The write backs.  Propogates modify times from handle to desciptor.
  1227.  *
  1228.  *----------------------------------------------------------------------------
  1229.  *
  1230.  */
  1231.  
  1232. ENTRY int
  1233. Fsutil_HandleDescWriteBack(shutdown, domain)
  1234.     Boolean    shutdown;    /* TRUE if the kernel is being shutdowned. */
  1235.     int        domain;        /* Domain number, -1 means all local domains */
  1236. {
  1237.     Hash_Search            hashSearch;
  1238.     register Fsio_FileIOHandle *handlePtr;
  1239.     register Fs_HandleHeader    *hdrPtr;
  1240.     register Hash_Entry        *hashEntryPtr;
  1241.     int                lockedDesc = 0;
  1242.  
  1243.     LOCK_MONITOR;
  1244.  
  1245.     Hash_StartSearch(&hashSearch);
  1246.  
  1247.     for (hashEntryPtr = Hash_Next(fileHashTable, &hashSearch);
  1248.          hashEntryPtr != (Hash_Entry *) NIL;  
  1249.      hashEntryPtr = Hash_Next(fileHashTable, &hashSearch)) {
  1250.     hdrPtr = (Fs_HandleHeader *) Hash_GetValue(hashEntryPtr);
  1251.     if (hdrPtr == (Fs_HandleHeader *)NIL) {
  1252.         /*
  1253.          * Handle has been removed.
  1254.          */
  1255.         continue;
  1256.     }
  1257.     if (hdrPtr->fileID.type != FSIO_LCL_FILE_STREAM) {
  1258.         continue;
  1259.     }
  1260.     if (domain >= 0 && hdrPtr->fileID.major != domain) {
  1261.         continue;
  1262.     }
  1263.     if (hdrPtr->flags & FS_HANDLE_LOCKED) {
  1264.         lockedDesc++;
  1265.         continue;
  1266.     }
  1267.     handlePtr = (Fsio_FileIOHandle *)hdrPtr;
  1268.     if (handlePtr->descPtr == (Fsdm_FileDescriptor *)NIL) {
  1269.         printf("Fsutil_HandleDescWriteBack, no descPtr for <%d,%d> \"%s\"\n",
  1270.         hdrPtr->fileID.major, hdrPtr->fileID.minor,
  1271.         Fsutil_HandleName(hdrPtr));
  1272.         continue;
  1273.     }
  1274.     (void)Fsdm_FileDescWriteBack(handlePtr, FALSE);
  1275.     }
  1276.  
  1277.     if (shutdown & lockedDesc) {
  1278.     printf("Fsutil_HandleDescWriteBack: %d descriptors still locked\n",
  1279.             lockedDesc);
  1280.     }
  1281.  
  1282.     UNLOCK_MONITOR;
  1283.  
  1284.     return(lockedDesc);
  1285. }
  1286.  
  1287.  
  1288. /*
  1289.  *----------------------------------------------------------------------
  1290.  *
  1291.  * Fsutil_ZeroHandleStats --
  1292.  *
  1293.  *    Zero the FS handle-related stats, while preserving state 
  1294.  *    information.
  1295.  *
  1296.  * Results:
  1297.  *    None.
  1298.  *
  1299.  * Side effects:
  1300.  *    None.
  1301.  *
  1302.  *----------------------------------------------------------------------
  1303.  */
  1304.  
  1305. ENTRY void
  1306. Fsutil_ZeroHandleStats()
  1307. {
  1308.     unsigned int maxNumber;    /* state variables to preserve */
  1309.     unsigned int exists;
  1310.     unsigned int lruEntries;
  1311.     unsigned int limbo;
  1312.  
  1313.     LOCK_MONITOR;
  1314.     maxNumber = fs_Stats.handle.maxNumber;
  1315.     exists = fs_Stats.handle.exists;
  1316.     lruEntries = fs_Stats.handle.lruEntries;
  1317.     limbo = fs_Stats.handle.limbo;
  1318.  
  1319.     bzero(&fs_Stats.handle, sizeof(fs_Stats.handle));
  1320.  
  1321.     fs_Stats.handle.maxNumber = maxNumber;
  1322.     fs_Stats.handle.exists = exists;
  1323.     fs_Stats.handle.lruEntries = lruEntries;
  1324.     fs_Stats.handle.limbo = limbo;
  1325.     UNLOCK_MONITOR;
  1326. }
  1327.